<?php
/**
 * Created by PhpStorm.
 * User: huangbo
 * Date: 2018/3/8
 * Time: 上午11:26
 */
namespace WsdServer\AppBase;

use DateTime;

use Doctrine\Common\Inflector\Inflector;

use Server\Components\Consul\ConsulServices;

class BaseBiz
{
    protected $orm_em;
    protected $orm_conn;
    protected $redis;

    protected $context;

    /**
     * BaseBiz constructor.
     * @param $orm_em
     * @param $orm_conn
     * @param $redis
     */
    public function __construct( $orm_em, $orm_conn, $redis )
    {
        $this->orm_em = $orm_em;
        $this->orm_conn = $orm_conn;
        $this->redis = $redis;
    }

    /**
     * 生成GUID
     */
    public function createGuid() {
        if (function_exists('com_create_guid')) {
            return com_create_guid();
        } else {
            mt_srand((double)microtime()*10000);
            $charid = strtoupper(md5(uniqid(rand(), true)));
            $hyphen = chr(45);
            $uuid   = chr(123)
                .substr($charid, 0, 8).$hyphen
                .substr($charid, 8, 4).$hyphen
                .substr($charid,12, 4).$hyphen
                .substr($charid,16, 4).$hyphen
                .substr($charid,20,12)
                .chr(125);
            return $uuid;
        }
    }

    public function entityArrayToArray($entityArray, $include=false, $exclude=false)
    {
        $result = Array();
        foreach ($entityArray as $key => $entity) {
            $result[$key] = $this->entityToArray($entity, $include, $exclude);
        }
        return $result;
    }

    /**
     * Convert doctrine-orm entity to array
     *
     * @param $entityObject
     * @param bool $include 转换输出包含Entity字段，空Aarray表示包含所有字段
     * @param bool $exclude 转换输出排除Entity字段
     * @return array
     */
    public function entityToArray($entityObject, $include=false, $exclude=false)
    {
        $data = array();

        $className = get_class($entityObject);
        $metaData = $this->orm_em->getClassMetadata($className);

        foreach ($metaData->fieldMappings as $field => $mapping)
        {
            if ( (is_array($include) && !in_array($field, $include)) ||
                (is_array($exclude) && in_array($field, $exclude)) )
            {
                //secho("entityToArray", "$className::$field...discard");
                continue;
            }
            $method = "get" . ucfirst($field);
            $value = call_user_func(array($entityObject, $method));
            if ( $mapping['type'] == "datetime" ){
                //$value = date_format($value, "Y-m-d H:i:s");
                if ( !empty($value) && $value instanceof datetime ){
                    $value = $value->format("Y-m-d H:i:s");         // datetime类型格式化输出
                }
            }elseif ( $mapping['type'] == "date" ) {
                if ( !empty($value) && $value instanceof datetime ){
                    $value = $value->format("Y-m-d");                      // date类型格式化输出
                }
            }
            $key = Inflector::tableize($field);                 // 驼峰命名转换为下划线命名
            $data[$key] = is_null($value) ? "" : $value;        // 转换null为""
            //secho("entityToArray", "$className::$field...[$key]=[$value]");
        }

        // Comment by hb on 2018-03-08: 暂不支持关联实体类转换Array
        /*
        foreach ($metaData->associationMappings as $field => $mapping)
        {
            // Sort of entity object
            $object = $metaData->reflFields[$field]->getValue($entityObject);
            $data[$field] = $this->entityToArray($object);
        }
        */

        return $data;
    }

    /**
     * Convert array to doctrine-orm entity
     * !!!= 不支持嵌套Array =!!!
     *
     * @param $entityObject : 待赋值的Entity对象
     * @param $data : 待转换的Array
     * @param bool $include : 转换输出包含Entity字段，空Aarray表示包含所有字段
     * @param bool $exclude : 转换输出排除Entity字段
     * @return mixed $entityObject
     */
    protected function arrayToEntity($entityObject, $data, $include=false, $exclude=false)
    {
        $className = get_class($entityObject);
        $metaData = $this->orm_em->getClassMetadata($className);

        foreach ($metaData->fieldMappings as $field => $mapping)
        {
            if ( (is_array($include) && !in_array($field, $include)) ||
                (is_array($exclude) && in_array($field, $exclude)) )
            {
                secho("arrayToEntity", "$className::$field...discard");
                continue;
            }
            $key = Inflector::tableize($field);                 // 驼峰命名转换为下划线命名
            if ( is_array($data) && key_exists($key, $data) && !empty($data[$key])){
                $value = $data[$key];
                if ( $mapping['type'] == "datetime" ){
                    $value = DateTime::createFromFormat("Y-m-d H:i:s", $data[$key]);
                }
                $method = "set" . ucfirst($field);
                call_user_func(array($entityObject, $method), $value);
                secho("arrayToEntity", "$className::$field...[$key]=[$value]");
            }
        }

        return $entityObject;
    }

    /**
     * 下划线命名转驼峰命名
     * 思路:
     * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
     * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
     * @param $uncamelized_words
     * @param string $separator
     * @return string
     */
    public function camelize($uncamelized_words, $separator='_')
    {
        $uncamelized_words = $separator. str_replace($separator, " ", strtolower($uncamelized_words));
        return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator );
    }

    /**
     * 驼峰命名转下划线命名
     * 思路:
     * 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
     * @param $camelCaps
     * @param string $separator
     * @return string
     */
    public function uncamelize($camelCaps, $separator='_')
    {
        return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
    }

    protected function callRpcService($serviceName, $method, $params, $context, $execServiceName="") {
        $data = Array( "id" => 1,  "jsonrpc" => "2.0", "method" => $method, "params" => $params );
        $data_json = json_encode($data);

        $rest = ConsulServices::getInstance()->getRESTService($serviceName, $context);
        $rest->addHeader("content-type", "application/json-rpc");
        $rest->setMethod("post");
        $rest->setData($data_json);

        if ($execServiceName==""){
            $execServiceName = $serviceName;
        }
        $resp = yield $rest->httpClient->coroutineExecute("/$execServiceName");
        $resp_body = json_decode($resp['body'], true);

        return $resp_body;
    }
}

